#include <sysbios/nano/List.h>
#include <xdc/runtime/System.h>

#include "package/internal/Kernel.xdc.h"

/*
 *  ======== initEvent ========
 */
Void Kernel_initEvent( Kernel_Event* event, UInt8 offset )
{
    event->elem.next = NULL;
    event->offset = offset;
}

/*
 *  ======== initFiber ========
 */
Void Kernel_initFiber( Kernel_Fiber* fiber, Kernel_Priority priority )
{
    fiber->eventList = &module->eventList[priority];
}

/*
 *  ======== post ========
 */
Void Kernel_post( Kernel_Event* event )
{
    Kernel_Fiber* fiber;
    List_Desc* eventList;

    fiber = Kernel_toFiber(event);
    eventList = fiber->eventList;

    List_put(eventList, &event->elem);

    if (eventList > module->curEventList) {
        Kernel_dispatch();
    }
}

/*
 *  ======== setReactor ========
 */
Void Kernel_setReactor( Kernel_Fiber* fiber, Kernel_Reactor reactor )
{
    fiber->reactor = reactor;
}

/*
 *  ======== setSignal ========
 */
Void Kernel_setSignal( Kernel_Event* event, Kernel_Signal signal )
{
    event->signal = signal;
}

/*
 *  ======== start ========
 */
Void Kernel_start()
{
    module->curEventList = NULL;
    Kernel_dispatch();
}

/* -------- internal functions -------- */

/*
 *  ======== dispatch ========
 */
Void Kernel_dispatch()
{
    Kernel_Fiber* fiber;
    Kernel_Event* event;
    List_Desc* eventList;

    for (;;) {

        eventList = module->curEventList = Kernel_maxEventList();
        if (eventList == NULL) {
            break;
        }

        do {
            event = List_get(eventList);
            fiber = Kernel_toFiber(event);
            (*fiber->reactor)(fiber, event->signal);
        } while (!List_empty(eventList));
    }
}

/*
 *  ======== maxEventList ========
 */
List_Desc* Kernel_maxEventList()
{
    Int p;

    for (p = Kernel_numPriorities - 1; p >= 0; p--) {
        if (!List_empty(&module->eventList[p])) {
            return &module->eventList[p];
        }
    }

    return NULL;
}

/*
 *  ======== toFiber ========
 */
Kernel_Fiber* Kernel_toFiber( Kernel_Event* event )
{
    return (Kernel_Fiber*)((Char*)event - event->offset);
}


